package com.youyi.utils;


import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.RescaleOp;
import java.io.*;
import java.util.Base64;

/**
 * @author youyi.time
 * @date 2024/11/23 14:02
 */
public class ImageUtils {

    /**
     * 读取图片文件到BufferedImage对象
     *
     * @param file 图片文件
     * @return BufferedImage对象
     * @throws IOException 如果无法读取文件
     */
    public static BufferedImage readImage(File file) throws IOException {
        return ImageIO.read(file);
    }

    /**
     * 将BufferedImage对象保存为图片文件
     *
     * @param image 要保存的图片
     * @param formatName 图片格式，例如"jpg"、"png"
     * @param file 输出的文件
     * @throws IOException 如果无法写入文件
     */
    public static void saveImage(BufferedImage image, String formatName, File file) throws IOException {

        ImageIO.write(image, formatName, file);
    }

    /**
     * 缩放图片
     *
     * @param image 原始图片
     * @param width 新宽度
     * @param height 新高度
     * @return 缩放后的图片
     */
    public static BufferedImage resizeImage(BufferedImage image, int width, int height) {
        BufferedImage resizedImage = new BufferedImage(width, height, image.getType());
        resizedImage.getGraphics().drawImage(image.getScaledInstance(width, height, java.awt.Image.SCALE_SMOOTH), 0, 0, null);
        return resizedImage;
    }

    /**
     * 转换图片格式
     *
     * @param sourceFile 源文件
     * @param targetFormat 目标格式，例如"jpg"、"png"
     * @param targetFile 目标文件
     * @throws IOException 如果读写文件出错
     */
    public static void convertImageFormat(File sourceFile, String targetFormat, File targetFile) throws IOException {
        BufferedImage image = readImage(sourceFile);
        saveImage(image, targetFormat, targetFile);
    }

    public static String imgToBase64(File file){
        if(file == null) throw new NullPointerException("file is null!");
        byte[] bytes = new byte[(int) file.length()];
        try {
            FileInputStream fis = new FileInputStream(file);
            fis.read(bytes);
        }catch (Exception e){
            e.printStackTrace();
        }
        return Base64.getEncoder().encodeToString(bytes);
    }


    /**
     * 将Base64字符串转换为图片文件
     *
     * @param base64String Base64字符串
     * @param targetFile 目标文件
     * @throws IOException 如果写入文件时发生错误
     */
    public static void base64ToImage(String base64String, File targetFile) throws IOException {
        byte[] bytes = Base64.getDecoder().decode(base64String);
        try (FileOutputStream fos = new FileOutputStream(targetFile)) {
            fos.write(bytes);
        }
    }


    /**
     * 等比缩放
     * @param image
     * @param newWidth
     * @param newHeight
     * @return
     */
    public static BufferedImage resize(BufferedImage image, int newWidth, int newHeight) {
        Image tmp = image.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
        BufferedImage resized = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = resized.createGraphics();
        g2d.drawImage(tmp, 0, 0, null);
        g2d.dispose();
        return resized;
    }


    /**
     * 旋转
     * @param image
     * @param angle
     * @return
     */
    public static BufferedImage rotate(BufferedImage image, double angle) {
        double sin = Math.abs(Math.sin(angle));
        double cos = Math.abs(Math.cos(angle));
        int origWidth = image.getWidth();
        int origHeight = image.getHeight();
        int newWidth = (int) Math.floor(origWidth * cos + origHeight * sin);
        int newHeight = (int) Math.floor(origHeight * cos + origWidth * sin);

        BufferedImage rotated = new BufferedImage(newWidth, newHeight, image.getType());
        Graphics2D g2d = rotated.createGraphics();
        AffineTransform at = AffineTransform.getTranslateInstance(newWidth / 2, newHeight / 2);
        at.rotate(angle);
        at.translate(-origWidth / 2, -origHeight / 2);
        g2d.setTransform(at);
        g2d.drawImage(image, 0, 0, null);
        g2d.dispose();

        return rotated;
    }

    /**
     * 图片剪裁
     * @param src
     * @param x
     * @param y
     * @param width
     * @param height
     * @return
     */
    public static BufferedImage crop(BufferedImage src, int x, int y, int width, int height) {
        return src.getSubimage(x, y, width, height);
    }

    /**
     * 调整亮度和对比度
     * @param image
     * @param brightness
     * @param contrast
     * @return
     */
    public static BufferedImage adjustBrightnessAndContrast(BufferedImage image, float brightness, float contrast) {
        RescaleOp rescaleOp = new RescaleOp(contrast, brightness, null);
        BufferedImage adjusted = rescaleOp.filter(image, null);
        return adjusted;
    }

    /**
     * 添加水印
     * @param baseImage 源图片
     * @param watermark 水印图片
     * @return
     */
    public static BufferedImage addWatermark(BufferedImage baseImage, BufferedImage watermark) {
        Graphics2D g2d = baseImage.createGraphics();
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f)); // 设置透明度
        int posX = (baseImage.getWidth() - watermark.getWidth()) / 2;
        int posY = (baseImage.getHeight() - watermark.getHeight()) / 2;
        g2d.drawImage(watermark, posX, posY, null);
        g2d.dispose();
        return baseImage;
    }



    /**
     * 直接在传入的 BufferedImage 对象上应用马赛克效果。
     *
     * @param image      要应用马赛克效果的图像对象
     * @param blockSize  马赛克块的大小（以像素为单位）
     */
    public static BufferedImage applyMosaicInPlace(BufferedImage image, int blockSize) {
        int width = image.getWidth(); // 获取图像宽度
        int height = image.getHeight(); // 获取图像高度

        BufferedImage result = new BufferedImage(width, height, image.getType());

        // 遍历图像，按照blockSize进行分块处理
        for (int x = 0; x < width; x += blockSize) {
            for (int y = 0; y < height; y += blockSize) {
                // 对每个分块计算平均颜色并填充该颜色
                int color = getAverageColor(image, x, y, blockSize);
                fillBlockInPlace(result, x, y, blockSize, color);
            }
        }

        return result;
    }

    /**
     * 计算给定区域内的平均颜色值。
     *
     * @param img        包含要计算的图像
     * @param startX     分块开始的X坐标
     * @param startY     分块开始的Y坐标
     * @param size       分块的大小（边长）
     * @return          返回该分块的平均颜色值
     */
    private static int getAverageColor(BufferedImage img, int startX, int startY, int size) {
        int sumR = 0, sumG = 0, sumB = 0;
        int count = 0;
        // 遍历分块中的所有像素点
        for (int x = startX; x < startX + size && x < img.getWidth(); x++) {
            for (int y = startY; y < startY + size && y < img.getHeight(); y++) {
                int pixel = img.getRGB(x, y); // 获取当前像素的颜色值
                int r = (pixel >> 16) & 0xff; // 提取红色通道值
                int g = (pixel >> 8) & 0xff;  // 提取绿色通道值
                int b = pixel & 0xff;         // 提取蓝色通道值
                sumR += r;
                sumG += g;
                sumB += b;
                count++;
            }
        }
        // 计算平均颜色值，并返回
        int avgR = sumR / count;
        int avgG = sumG / count;
        int avgB = sumB / count;
        return (avgR << 16) | (avgG << 8) | avgB;
    }

    /**
     * 使用指定颜色填充给定区域。
     *
     * @param img        包含要填充的图像
     * @param startX     填充区域开始的X坐标
     * @param startY     填充区域开始的Y坐标
     * @param size       填充区域的大小（边长）
     * @param color      用于填充的颜色值
     */
    private static void fillBlockInPlace(BufferedImage img, int startX, int startY, int size, int color) {
        // 将指定颜色应用于分块内所有像素
        for (int x = startX; x < startX + size && x < img.getWidth(); x++) {
            for (int y = startY; y < startY + size && y < img.getHeight(); y++) {
                img.setRGB(x, y, color); // 设置像素颜色
            }
        }
    }


    public static void main(String[] args) throws Exception {
        File file = new File("D:\\Desktop\\img\\微信图片_20241029231055.jpg");
        String x = imgToBase64(file);
        System.out.println(x);
    }
}